package cc.rengu.igas.channel.wechat.core.packswitch;

import cc.rengu.igas.channel.wechat.common.constant.WechatParamConstant;
import cc.rengu.igas.channel.wechat.common.constant.WechatTreeNodeConstant;
import cc.rengu.igas.channel.wechat.common.constant.WechatTxnNumConstant;
import cc.rengu.igas.channel.wechat.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.wechat.core.realize.WechatSignService;
import cc.rengu.igas.channel.wechat.core.realize.impl.WechatSignServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.DstChannelCfgMapper;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.service.common.entity.DstChannelCfg;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.AmountUtil;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.RandomUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import cc.rengu.utility.xml.XmlDocument;
import cc.rengu.utility.xml.XmlError;
import cc.rengu.utility.xml.XmlValue;
import com.alibaba.fastjson.JSON;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class CupsWechatNoticePackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {


    @Override
    public byte[] afterOutgoPackSwitch(byte[] arg0) throws Exception {
        //return "SUCCESS".getBytes();
        return arg0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        return 0;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        //赋值默认机构、渠道、交易细分
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String signBlockString = null;
        String signData;
        if (xmlTreeUtil.isExist(WechatTreeNodeConstant.WX_ORDER_ID)) {
            xmlTreeUtil.copyStringValue(WechatTreeNodeConstant.WX_ORDER_ID, TreeNodeConstant.FRONT_SEQ_NUM);
            xmlTreeUtil.copyStringValue(WechatTreeNodeConstant.WX_ORDER_ID, TreeNodeConstant.TRACE_NO);
        } else {
            String frontSeqNum = WechatParamConstant.PREFIX_SEQ_STRING + DateUtil.getCurrentDate() + DateUtil.getCurrentTime() + RandomUtil.getRandomInt();
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.FRONT_SEQ_NUM, frontSeqNum);
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRACE_NO, frontSeqNum);
        }

        /*根据url服务名转换交易码*/
        String mchntNo = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.MCHNT_NO);
        String sysSrcId = ChannelEnum.UPWX.getChannelType();
        DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
        List<DstChannelCfg> dstChannelCfgList = dstChannelCfgMapper.loadAllDstChannelCfg();
        if (dstChannelCfgList == null || dstChannelCfgList.isEmpty()) {
            rglog.error("无通道配置信息，未知法人行交易");
            return -1;
        }
        Predicate<DstChannelCfg> chnlIdFilter = p -> ChannelEnum.UPWX.getChannelType().equals(p.getDstChannelId());
        Predicate<DstChannelCfg> mchntNoFilter = p -> mchntNo.equals(p.getProviderMchntNo());
        dstChannelCfgList = dstChannelCfgList.stream().filter(chnlIdFilter.and(mchntNoFilter)).collect(Collectors.toList());
        if (dstChannelCfgList.isEmpty()) {
            rglog.error("根据通道id<{}>、微信商户号<{}>查无无通道配置信息，未知法人行交易", ChannelEnum.UPWX.getChannelType(), mchntNo);
            return -1;
        }
        String instId = dstChannelCfgList.get(0).getInstId();
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.INST_ID, instId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, WechatParamConstant.TUNL_ID_CUPSWXZF);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, AppParamConstant.DEFAULT_BIZ_TYPE);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_INST_ID, instId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_SRC_SYS_ID, WechatParamConstant.TUNL_ID_CUPSWXZF);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_CHANNEL_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_BIZ_TYPE, AppParamConstant.DEFAULT_BIZ_TYPE);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, WechatTxnNumConstant.T00CH200);
        if (xmlTreeUtil.isExist(TreeNodeConstant.ORDER_AMT)) {
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.ORDER_AMT, AmountUtil.changeF2Y(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.ORDER_AMT)));
        }
        if (xmlTreeUtil.isExist("cashAmt")) {
            xmlTreeUtil.setXmlTreeStringValue("cashAmt", AmountUtil.changeF2Y(xmlTreeUtil.getXmlTreeStringValue("cashAmt")));
        }
        if (xmlTreeUtil.isExist("settleAmt")) {
            xmlTreeUtil.setXmlTreeStringValue("settleAmt", AmountUtil.changeF2Y(xmlTreeUtil.getXmlTreeStringValue("settleAmt")));
        }
        if (xmlTreeUtil.isExist("couponAmt")) {
            xmlTreeUtil.setXmlTreeStringValue("couponAmt", AmountUtil.changeF2Y(xmlTreeUtil.getXmlTreeStringValue("couponAmt")));
        }
        if (!xmlTreeUtil.isExist("sign")) {
            rglog.error("没有sign字段，不验证签名");
            return 0;
        }
        signData = xmlTreeUtil.getXmlTreeStringValue("sign");
        if (xmlTreeUtil.isExist("signBlockString")) {
            signBlockString = xmlTreeUtil.getXmlTreeStringValue("signBlockString");
        }
        /* 获取通道配置信息 */
        /* 通道状态检查 */
        DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
        DstChannelInfo dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, WechatParamConstant.TUNL_ID_CUPSWXZF);
        if (null == dstChannelInfo) {
            rglog.error("获取通道<{}>配置信息失败!", WechatParamConstant.TUNL_ID_CUPSWXZF);
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        } else {
            if (AppParamConstant.NO.equals(dstChannelInfo.getDstChannelStatus())) {
                rglog.error("通道状态异常,status:<{}>", dstChannelInfo.getDstChannelStatus());
                throw new BizException(RespCodeEnum.CHANNEL_STATUS_UNNORMAL.getRespCode(), RespCodeEnum.CHANNEL_STATUS_UNNORMAL.getRespDesc());
            }
        }
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfgList.get(0).getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
            /* 获取敏感信息加密证书 */
            Optional<SecPlanInfo> checkSignSecPlanOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.VERIFY_CERT_TYPE)).findFirst();
            if (checkSignSecPlanOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(instId + checkSignSecPlanOpt.get().getSecPlanId() + checkSignSecPlanOpt.get().getSecPlanType());
                if (null == certInfo) {
                    rglog.error("获取通道<{}>配置信息失败!", instId + checkSignSecPlanOpt.get().getSecPlanId() + checkSignSecPlanOpt.get().getSecPlanType());
                    throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
                }
                WechatSignService signService = new WechatSignServiceImpl();
                /* 验证签名 */
                if (signService.verifySignString(signData, signBlockString, certInfo)) {
                    rglog.info("签名验证成功!");
                    return 0;
                } else {
                    rglog.error("签名验证失败!");
                    return -1;
                }
            }
        }
        return -1;
    }

    @Override
    public byte[] beforeInComPackSwitch(byte[] arg0) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String signData;
        /* 获取数字签名字符串 */
        String xmlBefore = new String(arg0);
        XmlDocument xmlDocument = new XmlDocument();
        XmlError xmlError = xmlDocument.loadString(xmlBefore);
        if (!xmlError.isSuccess()) {
            rglog.error("接收报文异常!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            XmlValue xmlvalue = xmlDocument.getValue("sign", xmlError);
            if (null == xmlvalue) {
                rglog.debug("无签域，不进行签名校验!");
                return arg0;
            }
            signData = xmlvalue.getText();
            if (null == signData) {
                rglog.debug("无签域，不进行签名校验!");
                return arg0;
            }
            /* 生成生成数字签名的字符串 */
            String signBlockString = generateSignBlockString(xmlBefore);
            if (null == signBlockString) {
                rglog.error("生成加签Block失败!");
                throw new BizException(RespCodeEnum.GENERATE_SIGN_BLOCK_ERROR.getRespCode(), RespCodeEnum.GENERATE_SIGN_BLOCK_ERROR.getRespDesc());
            }
            rglog.debug("加签Block:<{}>", signBlockString);
            xmlTreeUtil.setXmlTreeStringValue("signBlockString", signBlockString);

        }
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.MESSAGE, xmlBefore);
        return arg0;
    }

    /**
     * 生成加签Block
     *
     * @param xmlString 原始报文
     * @return 加签BLOCK
     */
    private String generateSignBlockString(String xmlString) {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        try {
            if (null != xmlString && 0 != xmlString.trim().length()) {
                ArrayList<String> arrayList = new ArrayList<>();
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder documentBuilder = factory.newDocumentBuilder();
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xmlString.getBytes());
                Document document = documentBuilder.parse(byteArrayInputStream);
                NodeList allNodes = document.getFirstChild().getChildNodes();
                Node node;
                int i = 0;
                while (i < allNodes.getLength()) {
                    node = allNodes.item(i);
                    if (node instanceof Element) {
                        if (!"sign".equals(node.getNodeName()) && null != node.getTextContent() && 0 != node.getTextContent().length()) {
                            arrayList.add(node.getNodeName() + "=" + node.getTextContent() + "&");
                        }
                    }
                    i++;
                }
                String[] strArray = arrayList.toArray(new String[0]);
                Arrays.sort(strArray);
                StringBuilder stringBuffer = new StringBuilder();
                for (i = 0; i < strArray.length; i++) {
                    stringBuffer.append(strArray[i]);
                }
                return stringBuffer.substring(0, stringBuffer.length() - 1);
            }
        } catch (Exception e) {
            rglog.error("系统异常!");
            return null;
        }
        return null;
    }

}
